home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / Form / Sources / ScrollEd.cpp < prev    next >
Encoding:
Text File  |  1996-08-16  |  16.8 KB  |  544 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                ScrollEd.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Author:                Laurent Delamare
  7. //
  8. //    Copyright:            (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9. //
  10. //========================================================================================
  11.  
  12. #include "Form.hpp"
  13.  
  14. #ifndef SCROLLED_H
  15. #include "ScrollEd.h"
  16. #endif
  17.  
  18. #ifndef FRAME_H
  19. #include "Frame.h"
  20. #endif
  21.  
  22. #ifndef EDITCMD_H
  23. #include "EditCmd.h"
  24. #endif
  25.  
  26. #ifndef FWPART_H
  27. #include "FWPart.h"
  28. #endif
  29.  
  30. #ifndef FWEVENT_H
  31. #include "FWEvent.h"
  32. #endif
  33.  
  34. #ifndef FWEVEDEF_H
  35. #include "FWEveDef.h"
  36. #endif
  37.  
  38. #ifndef FWSCLBAR_H
  39. #include "FWSclBar.h"
  40. #endif
  41.  
  42. #ifndef FWSCLNOT_H
  43. #include "FWSclNot.h"
  44. #endif
  45.  
  46. #ifndef FWCONTXT_H
  47. #include "FWContxt.h"
  48. #endif
  49.  
  50. //========================================================================================
  51. // RunTime Info
  52. //========================================================================================
  53.  
  54. #ifdef FW_BUILD_MAC
  55. #pragma segment odfform
  56. #endif
  57.  
  58. FW_DEFINE_CLASS_M3(CScrollEdit, FW_CEditView, FW_MReceiver, FW_MNotifier);
  59. FW_DEFINE_AUTO(CScrollEdit)
  60.  
  61. const FW_ClassTypeConstant LScrollEd = FW_TYPE_CONSTANT('S','e','d','v');
  62. FW_REGISTER_ARCHIVABLE_CLASS(LScrollEd, CScrollEdit, CScrollEdit::Create, FW_CView::Read, CScrollEdit::Destroy, FW_CView::Write)
  63.  
  64. //========================================================================================
  65. // CScrollEdit
  66. //========================================================================================
  67.  
  68. // Documentation
  69. // -------------
  70. // CScrollEdit adds scrolling functionalities to FW_CEditView and adds support for
  71. // Undo/Redo clipboard commands
  72. //
  73. // CScrollEdit inherits from FW_MReceiver in order to respond to scrolling notifications
  74. //
  75. // CScrollEdit must disable its clipboard commands when the
  76. // view is deleted (see discussion in CEditViewCommand::HandleNotification)
  77. //
  78. // A CScrollEdit object requires a vertical and/or an horizontal scrollbars.  
  79. // It can be created from resources, see the type RScrollEdit in Form's views.fr
  80.  
  81. //----------------------------------------------------------------------------------------
  82. // CScrollEdit::CScrollEdit
  83. //----------------------------------------------------------------------------------------
  84.  
  85. CScrollEdit::CScrollEdit (Environment* ev, 
  86.                         FW_CSuperView* container, 
  87.                         ODID viewId, 
  88.                         const FW_CRect& bounds,
  89.                         FW_CScrollBar* horzSB,
  90.                         FW_CScrollBar* vertSB,
  91.                         const FW_CString& str, 
  92.                         const FW_CFont& font,
  93.                         short maxChars, 
  94.                         unsigned short attributes,
  95.                         FW_Fixed textWidth) 
  96.     : FW_CEditView(ev, container, viewId, bounds, str, font, maxChars, attributes),
  97.     FW_MReceiver()
  98. {
  99.     fScrollbars[FW_kHorizontal] = horzSB;
  100.     fScrollbars[FW_kVertical] = vertSB;
  101.     
  102.     // use the view width by default
  103.     fWidth = (textWidth == FW_kFixed0) ? bounds.Size().x : textWidth;
  104.             
  105.     Initialize(ev);
  106. }
  107.  
  108. //----------------------------------------------------------------------------------------
  109. // CScrollEdit::CScrollEdit
  110. //----------------------------------------------------------------------------------------
  111. CScrollEdit::CScrollEdit(Environment* ev)
  112.     : FW_CEditView(ev),
  113.     FW_MReceiver()
  114. {
  115. }
  116.  
  117. //----------------------------------------------------------------------------------------
  118. // CScrollEdit::Initialize
  119. //----------------------------------------------------------------------------------------
  120.  
  121. void CScrollEdit::Initialize(Environment* ev)
  122. {
  123.     // scrolling view responds to scrollbar notifications
  124.     if (fScrollbars[FW_kVertical]) 
  125.         AddInterest(FW_CInterest(fScrollbars[FW_kVertical], FW_kScrollMsg));
  126.  
  127.     if (fScrollbars[FW_kHorizontal]) 
  128.         AddInterest(FW_CInterest(fScrollbars[FW_kHorizontal], FW_kScrollMsg));
  129.  
  130.     AdjustTERects(ev);
  131.     UpdateScrollParameters(ev);
  132.     UpdateScrollUnits(ev);
  133. }
  134.  
  135. //----------------------------------------------------------------------------------------
  136. // CScrollEdit::~CScrollEdit
  137. //----------------------------------------------------------------------------------------
  138.  
  139. CScrollEdit::~CScrollEdit ()
  140. {
  141.     // Don't delete the scroll bars, we don't own them! 
  142.     
  143.     if (fScrollbars[FW_kHorizontal])
  144.     {
  145.         FW_CInterest interest(fScrollbars[FW_kHorizontal], FW_kScrollMsg);
  146.         RemoveInterest(interest);
  147.     }
  148.     if (fScrollbars[FW_kVertical])
  149.     {
  150.         FW_CInterest interest(fScrollbars[FW_kVertical], FW_kScrollMsg);
  151.         RemoveInterest(interest);
  152.     }
  153. }
  154.  
  155. //----------------------------------------------------------------------------------------
  156. // CScrollEdit::AdjustTERects
  157. //----------------------------------------------------------------------------------------
  158.  
  159. void CScrollEdit::AdjustTERects(Environment* ev)
  160. {
  161.     TEHandle teHdl = (TEHandle)GetPlatformEditHandle(ev);
  162.     TEPtr te = *teHdl;
  163.     
  164.     // Set viewRect height to a multiple of lines to avoid cutting lines
  165.     te->viewRect.bottom = (((te->viewRect.bottom - te->viewRect.top) / te->lineHeight)
  166.                             * te->lineHeight) + te->viewRect.top;
  167.  
  168.     // Adjust width of destination rectangle for text scrolling horizontally
  169.     if (fScrollbars[FW_kHorizontal])
  170.         te->destRect.right = te->destRect.left + FW_FixedToInt(fWidth);
  171. }
  172.  
  173. //----------------------------------------------------------------------------------------
  174. // CScrollEdit::SizeChanged
  175. //----------------------------------------------------------------------------------------
  176.  
  177. void CScrollEdit::SizeChanged (Environment* ev, const FW_CPoint& oldSize)
  178. {
  179.     // call base class to update the TEd viewRect
  180.     FW_CEditView::SizeChanged(ev, oldSize);
  181.     
  182.     AdjustTERects(ev);
  183.     
  184.     // We use the fact that the scrollbars have already been resized because they
  185.     // were created before the CScrollEdit object.
  186.     UpdateScrollParameters(ev);
  187.     UpdateScrollUnits(ev);    
  188. }
  189.  
  190. //----------------------------------------------------------------------------------------
  191. // CScrollEdit::UpdateScrollUnits
  192. //----------------------------------------------------------------------------------------
  193.  
  194. void CScrollEdit::UpdateScrollUnits(Environment* ev)
  195. {
  196.     TEHandle teHdl = (TEHandle)GetPlatformEditHandle(ev);
  197.     FW_CScrollBar* sb = fScrollbars[FW_kHorizontal];
  198.  
  199.     if (sb)
  200.     {
  201.         short major = (**teHdl).viewRect.right - (**teHdl).viewRect.left;
  202.         short minor = major / 10;
  203.         sb->SetMinorScrollUnits(ev, FW_IntToFixed(minor));
  204.         sb->SetMajorScrollUnits(ev, FW_IntToFixed(major));    
  205.     }
  206.  
  207.     sb = fScrollbars[FW_kVertical];
  208.     if (sb)
  209.     {
  210.         short major = ((**teHdl).viewRect.bottom - (**teHdl).viewRect.top) / (**teHdl).lineHeight;
  211.         sb->SetMajorScrollUnits(ev, FW_IntToFixed(major));    
  212.         // minor scroll unit is always 1 line.
  213.     }
  214. }
  215.  
  216. //----------------------------------------------------------------------------------------
  217. // CScrollEdit::UpdateScrollParameters
  218. //----------------------------------------------------------------------------------------
  219. void CScrollEdit::UpdateScrollParameters(Environment* ev)
  220. {
  221.     AdjustScrollbar(ev, FW_kVertical);
  222.     AdjustScrollbar(ev, FW_kHorizontal);
  223.     
  224.     // Must also scroll the Ted to match up the new scrollbar values
  225.     // in case a scroll bar became inactive and the Ted was already scrolled
  226.     AdjustTE(ev);
  227. }
  228.  
  229. //----------------------------------------------------------------------------------------
  230. // CScrollEdit::AdjustTE
  231. //----------------------------------------------------------------------------------------
  232. void CScrollEdit::AdjustTE(Environment* ev)
  233. {
  234.     // We must create a graphic context and adjust the Mac text-edit
  235.     // before making any native TE calls
  236.     FW_CViewContext gc (ev, this, GetFrame(ev)->GetActiveFacet(ev));
  237.     MacAdjustRects (ev, gc);
  238.     
  239.     TEHandle teHdl = (TEHandle)GetPlatformEditHandle(ev);
  240.     
  241.     FW_CScrollBar* sb = fScrollbars[FW_kHorizontal];
  242.     short hScroll = 0;
  243.     if (sb)
  244.         hScroll = ((**teHdl).viewRect.left - (**teHdl).destRect.left) - FW_FixedToInt(sb->GetScrollPos(ev));
  245.  
  246.     sb = fScrollbars[FW_kVertical];
  247.     short vScroll = 0;
  248.     if (sb)
  249.         vScroll = ((**teHdl).viewRect.top - (**teHdl).destRect.top) - 
  250.                     (FW_FixedToInt(sb->GetScrollPos(ev)) * ((**teHdl).lineHeight));
  251.         
  252.     TEScroll(hScroll, vScroll, teHdl);
  253. }
  254.  
  255. //----------------------------------------------------------------------------------------
  256. // CScrollEdit::AdjustScrollbar
  257. //----------------------------------------------------------------------------------------
  258. // Code borrowed from the MPW example TEDocument.cp
  259.  
  260. void CScrollEdit::AdjustScrollbar(Environment* ev, FW_XYSelector direction)
  261. {
  262.     FW_CScrollBar* sb = fScrollbars[direction];
  263.     if (sb == NULL)
  264.         return;
  265.  
  266.     TEHandle teHdl = (TEHandle)GetPlatformEditHandle(ev);
  267.     TEPtr     te = *teHdl;
  268.     int max = 0;
  269.     int oldMax = FW_FixedToInt(sb->GetScrollMax(ev));
  270.     
  271.     if (direction == FW_kVertical)
  272.     {
  273.         short lines = te->nLines;
  274.         // add 1 line if last char is a return
  275.         if ( *(*te->hText + te->teLength - 1) == 13 )
  276.             lines += 1;
  277.         max = lines - (( te->viewRect.bottom - te->viewRect.top ) / te->lineHeight);
  278.     }
  279.     else
  280.     {
  281.         max = FW_FixedToInt(fWidth) - ( te->viewRect.right - te->viewRect.left );    
  282.     }
  283.  
  284.     if (max < 0) max = 0;
  285.     
  286.     // Must convert to fixed number for SetScrollMax
  287.     sb->SetScrollMax(ev, FW_IntToFixed(max));
  288.  
  289.     te = *teHdl;
  290.     int value;
  291.     int oldValue = FW_FixedToInt(sb->GetScrollPos(ev));
  292.     
  293.     if (direction == FW_kVertical)
  294.         value = ( te->viewRect.top - te->destRect.top ) / te->lineHeight;
  295.     else 
  296.         value = te->viewRect.left - te->destRect.left;
  297.     
  298.     if (value < 0)
  299.         value = 0;
  300.     else if (value > max)
  301.         value = max;
  302.     
  303.     // Must convert to fixed number for SetScrollPos
  304.     sb->SetScrollPos(ev, FW_IntToFixed(value));
  305.     
  306.     if (value == oldValue && max != oldMax)
  307.         sb->RedrawControl(ev);
  308. }
  309.  
  310. //----------------------------------------------------------------------------------------
  311. // CScrollEdit::DoAdjustMenus
  312. //----------------------------------------------------------------------------------------
  313.  
  314. FW_Boolean CScrollEdit::DoAdjustMenus (Environment *ev, FW_CMenuBar* menuBar, 
  315.                         FW_Boolean hasMenuFocus, FW_Boolean isRoot)
  316. {
  317.     // Let base class adjust the Edit menu first
  318.     FW_CEditView::DoAdjustMenus(ev, menuBar, hasMenuFocus, isRoot);
  319.  
  320.     if (hasMenuFocus)
  321.     {
  322.         // update the Paste command
  323.         FW_Boolean hasClipboard = GetFrame(ev)->HasPropertyOnClipboard(ev, kODPropContents, FW_CPart::gMacTEXTDataType);
  324.         menuBar->EnableCommand (ev, kODCommandPaste, hasClipboard);
  325.     }
  326.     return FALSE;    // let parent views adjust their menus
  327. }
  328.  
  329. //----------------------------------------------------------------------------------------
  330. // CScrollEdit::DoMenu
  331. //----------------------------------------------------------------------------------------
  332.  
  333. FW_Boolean CScrollEdit::DoMenu (Environment* ev, const FW_CMenuEvent& event)
  334. {
  335.     ODCommandID id = event.GetCommandID(ev);
  336.     FW_Boolean commandHandled = true;
  337.     
  338.     switch (id) 
  339.     {
  340.         case kODCommandCut: 
  341.         case kODCommandCopy: 
  342.         case kODCommandPaste: 
  343.         case kODCommandClear: 
  344.             // Ask the frame to create an EditView command:
  345.             // if the command is created, execute it
  346.             // if the frame didn't implement NewClipboardCommand(), revert to default behavior
  347.             CEditViewCommand* cmd = (CEditViewCommand*)GetFrame(ev)->NewClipboardCommand(ev, id);
  348.             if (cmd)
  349.             {
  350.                 cmd->SetEditView(this);
  351.                 if (cmd->GetSelection(ev) == NULL)
  352.                 {
  353.                     // The presentation doesn't have any selection, we create one on the fly
  354.                     cmd->SetSelection(FW_NEW(CEditViewSelection, (ev, this)));
  355.                 }
  356.                 cmd->Execute(ev);                
  357.             }
  358.             else
  359.             {
  360.                 DoTECommand(ev, id, true);    // Will use normal scrap
  361.             }
  362.             UpdateScrollParameters(ev);
  363.             break;
  364.  
  365.         default:
  366.             commandHandled = FW_CEditView::DoMenu (ev, event); // call base class
  367.  
  368.             if (id == kODCommandSelectAll) 
  369.                 UpdateScrollParameters(ev);
  370.     }
  371.     return commandHandled;
  372. }
  373.  
  374. //----------------------------------------------------------------------------------------
  375. // CScrollEdit::HandleNotification
  376. //----------------------------------------------------------------------------------------
  377.  
  378. void CScrollEdit::HandleNotification(Environment* ev, const FW_CNotification& notification)
  379. {
  380.     if (notification.GetMessage() == FW_kScrollMsg)
  381.     {
  382.         const FW_CScrollNotification& scrollNfy = (FW_CScrollNotification&) notification;
  383.     
  384.         FW_XYSelector direction = scrollNfy.GetDirection(ev);
  385.         int amount = FW_FixedToInt(-scrollNfy.GetDelta(ev));
  386.         
  387.         if (amount != 0)
  388.         {
  389.             TEHandle teHdl = (TEHandle)GetPlatformEditHandle(ev);
  390.             
  391.             // We must create a graphic context and adjust the Mac text-edit
  392.             // before making any native TE calls
  393.             FW_CViewContext gc (ev, this, GetFrame(ev)->GetActiveFacet(ev));
  394.             MacAdjustRects (ev, gc);
  395.             
  396.             if (direction == FW_kVertical)
  397.                 TEScroll(0, amount * (*teHdl)->lineHeight, teHdl);
  398.             else
  399.                 TEScroll(amount, 0, teHdl);
  400.         }
  401.     }
  402. }
  403.  
  404. //----------------------------------------------------------------------------------------
  405. // CScrollEdit::DoVirtualKey
  406. //----------------------------------------------------------------------------------------
  407.  
  408. FW_Boolean CScrollEdit::DoVirtualKey (Environment* ev, const FW_CVirtualKeyEvent & event)
  409. {
  410.     // Let base class handle the key first
  411.     FW_Boolean keyHandled = FW_CEditView::DoVirtualKey(ev, event);
  412.  
  413.     short    keyCode = event.GetKeyCode(ev);
  414.     
  415.     // Handle PageUp and PageDown keys
  416.     if (keyHandled == false && (keyCode == FW_kVKPageUp || keyCode == FW_kVKPageDown))
  417.     {
  418.         TEHandle teHdl = (TEHandle)GetPlatformEditHandle(ev);
  419.         short amount = ((**teHdl).viewRect.bottom - (**teHdl).viewRect.top);
  420.         if (keyCode == FW_kVKPageDown)
  421.             amount = - amount;
  422.             
  423.         FW_CViewContext gc (ev, this, GetFrame(ev)->GetActiveFacet(ev));
  424.         MacAdjustRects (ev, gc);
  425.  
  426.         TEScroll(0, amount, teHdl);
  427.  
  428.         keyHandled = true;
  429.         UpdateScrollParameters(ev);
  430.     }
  431.     
  432.     return keyHandled;
  433. }
  434.  
  435. //----------------------------------------------------------------------------------------
  436. // CScrollEdit::DoCharKey
  437. //----------------------------------------------------------------------------------------
  438.  
  439. FW_Boolean CScrollEdit::DoCharKey (Environment* ev, const FW_CCharKeyEvent& event)
  440. {
  441.     // Let base class handle the character first
  442.     FW_Boolean handled = FW_CEditView::DoCharKey(ev, event);
  443.     
  444.     // Update scrollbars
  445.     if (handled) 
  446.         UpdateScrollParameters(ev);
  447.     
  448.     return handled;
  449. }
  450.  
  451. //----------------------------------------------------------------------------------------
  452. // CScrollEdit::DoMouseDown
  453. //----------------------------------------------------------------------------------------
  454.  
  455. FW_Boolean CScrollEdit::DoMouseDown (Environment* ev, const FW_CMouseEvent& event)
  456. {
  457.     FW_Boolean handled = FW_CEditView::DoMouseDown(ev, event);
  458.     
  459.     // Adjust the scrollbars here after auto-scrolling may have occured 
  460.     UpdateScrollParameters(ev);
  461.     
  462.     return handled;
  463. }
  464.  
  465. //----------------------------------------------------------------------------------------
  466. //    CScrollEdit::SetText
  467. //----------------------------------------------------------------------------------------
  468.  
  469. void CScrollEdit::SetText (Environment * ev, const FW_CString& str)
  470. {
  471.     FW_CEditView::SetText(ev, str);
  472.     UpdateScrollParameters(ev);
  473. }
  474.  
  475. //----------------------------------------------------------------------------------------
  476. //    CScrollEdit::Create
  477. //----------------------------------------------------------------------------------------
  478.  
  479. void* CScrollEdit::Create(FW_CReadableStream& stream, FW_ClassTypeConstant type)
  480. {
  481. FW_UNUSED(stream);
  482. FW_UNUSED(type);
  483.     FW_SOMEnvironment ev;
  484.     return FW_NEW(CScrollEdit, (ev));
  485. }
  486.  
  487. //----------------------------------------------------------------------------------------
  488. //    CScrollEdit::Destroy
  489. //----------------------------------------------------------------------------------------
  490.  
  491. void CScrollEdit::Destroy(void* object, FW_ClassTypeConstant type)
  492. {
  493. FW_UNUSED(type);
  494.     CScrollEdit* self = (CScrollEdit*) object;
  495.     delete self;
  496. }
  497.  
  498. //----------------------------------------------------------------------------------------
  499. //    CScrollEdit::Flatten
  500. //----------------------------------------------------------------------------------------
  501.  
  502. void CScrollEdit::Flatten(Environment* ev, FW_CWritableStream& stream) const
  503. {
  504.     FW_CEditView::Flatten(ev, stream);
  505.  
  506.     ODID horizScrollBarID = (fScrollbars[FW_kHorizontal] == NULL) ? kODNULLID :
  507.                                 fScrollbars[FW_kHorizontal]->GetViewId(ev);
  508.     ODID vertScrollBarID = (fScrollbars[FW_kVertical] == NULL) ? kODNULLID :
  509.                                 fScrollbars[FW_kVertical]->GetViewId(ev);
  510.  
  511.     stream << horizScrollBarID << vertScrollBarID << fWidth;
  512. }
  513.  
  514. //----------------------------------------------------------------------------------------
  515. //    CScrollEdit::InitializeFromStream
  516. //----------------------------------------------------------------------------------------
  517.  
  518. void CScrollEdit::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  519. {
  520.     FW_CEditView::InitializeFromStream(ev, stream);
  521.     
  522.     ODID horizScrollBarID;
  523.     ODID vertScrollBarID;
  524.     stream >> horizScrollBarID >> vertScrollBarID >> fWidth;
  525.  
  526.     FW_CSuperView* parentView = GetSuperView(ev);
  527.     FW_ASSERT(parentView);
  528.     
  529.     FW_CView* hScrollBarView = NULL;
  530.     if (horizScrollBarID != kODNULLID)
  531.         hScrollBarView = parentView->FindViewById(ev, horizScrollBarID);
  532.  
  533.     FW_CView* vScrollBarView = NULL;
  534.     if (vertScrollBarID != kODNULLID)
  535.         vScrollBarView = parentView->FindViewById(ev, vertScrollBarID);
  536.  
  537.     fScrollbars[FW_kHorizontal] = FW_DYNAMIC_CAST(FW_CScrollBar, hScrollBarView);
  538.     fScrollbars[FW_kVertical] = FW_DYNAMIC_CAST(FW_CScrollBar, vScrollBarView);
  539.     
  540.     Initialize(ev);
  541. }
  542.  
  543.  
  544.